package com.share.rules.config;

import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.ReleaseId;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DroolsHelper {
    private static final Logger logger = LoggerFactory.getLogger(DroolsHelper.class);
    private static final KieServices kieServices = KieServices.Factory.get();

    // 使用ConcurrentHashMap实现线程安全的缓存
    private static final Map<Integer, KieContainer> containerCache = new ConcurrentHashMap<>();
    private static final Map<Integer, String> ruleCache = new ConcurrentHashMap<>();

    // 静态工具类，私有构造函数
    private DroolsHelper() {
    }

    /**
     * 从规则字符串加载并返回KieSession
     * 使用规则字符串的哈希码作为缓存键
     */
    public static KieSession loadForRule(String drlStr) {
        if (drlStr == null || drlStr.trim().isEmpty()) {
            throw new IllegalArgumentException("规则字符串不能为空");
        }

        int ruleHash = drlStr.hashCode();
        KieContainer kieContainer = getOrCreateKieContainer(ruleHash, drlStr);

        // 每次创建新的KieSession实例（KieSession不是线程安全的）
        return kieContainer.newKieSession();
    }

    /**
     * 获取或创建KieContainer（带缓存）
     */
    private static KieContainer getOrCreateKieContainer(int ruleHash, String drlStr) {
        // 检查缓存中是否已有该规则
        if (containerCache.containsKey(ruleHash) && ruleCache.get(ruleHash).equals(drlStr)) {
            logger.debug("使用缓存的KieContainer，规则哈希: {}", ruleHash);
            return containerCache.get(ruleHash);
        }

        // 规则发生变化或首次加载，创建新的KieContainer
        synchronized (DroolsHelper.class) {
            // 双重检查锁定
            if (containerCache.containsKey(ruleHash) && ruleCache.get(ruleHash).equals(drlStr)) {
                return containerCache.get(ruleHash);
            }

            // 清理旧的KieContainer（如果有）
            if (containerCache.containsKey(ruleHash)) {
                try {
                    containerCache.get(ruleHash).dispose();
                } catch (Exception e) {
                    logger.error("关闭旧的KieContainer失败", e);
                }
            }

            // 创建新的KieContainer
            KieContainer newContainer = createKieContainer(drlStr, ruleHash);

            // 更新缓存
            containerCache.put(ruleHash, newContainer);
            ruleCache.put(ruleHash, drlStr);

            logger.info("创建新的KieContainer，规则哈希: {}", ruleHash);
            return newContainer;
        }
    }

    /**
     * 创建新的KieContainer
     */
    private static KieContainer createKieContainer(String drlStr, int ruleHash) {
        KieFileSystem kfs = kieServices.newKieFileSystem();
        kfs.write("src/main/resources/rules/" + ruleHash + ".drl", drlStr);

        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs);
        kieBuilder.buildAll();

        if (kieBuilder.getResults().hasMessages(Message.Level.ERROR)) {
            String errorMsg = "规则编译错误: " + kieBuilder.getResults().toString();
            logger.error(errorMsg);
            throw new RuntimeException(errorMsg);
        }

        ReleaseId releaseId = kieServices.getRepository().getDefaultReleaseId();
        return kieServices.newKieContainer(releaseId);
    }

    /**
     * 清理缓存并释放所有KieContainer资源
     */
    public static void clearCache() {
        synchronized (DroolsHelper.class) {
            for (KieContainer container : containerCache.values()) {
                try {
                    container.dispose();
                } catch (Exception e) {
                    logger.error("关闭KieContainer失败", e);
                }
            }
            containerCache.clear();
            ruleCache.clear();
            logger.info("已清理所有Drools缓存");
        }
    }

    /**
     * 关闭KieSession并释放资源
     */
    public static void closeSession(KieSession kieSession) {
        if (kieSession != null) {
            try {
                kieSession.dispose();
                logger.debug("已关闭KieSession");
            } catch (Exception e) {
                logger.error("关闭KieSession失败", e);
            }
        }
    }
}